package cn.yhr.summerboot.context;

import cn.yhr.summerboot.context.annon.Ioc;
import cn.yhr.summerboot.context.exception.IocException;
import cn.yhr.summerboot.core.util.StringCaseUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Tittle PackageScanner
 * @Description
 * @Author yhr
 * @Date 2018/11/26 10:47
 * @Version 1.0
 */
public class PackageScanner {

    private static Logger logger = LoggerFactory.getLogger(PackageScanner.class);

    private static ClassLoader classLoader = PackageScanner.class.getClassLoader();

    private static String packages=null;

    /**
     * ioc容器里面的所有类
     */
    private static List<Class> classes = new ArrayList();

    private static IocApplication ioc=IocApplication.getApplication();

    /**
     * 获取扫描的包下面所有的class文件
     */
    public static List<Class> init(String packages){
        PackageScanner.packages = packages;
        try {
            //递归扫描包
            URI strPath = classLoader.getResource(packages.replace(".", "/")).toURI();
            recursionPath(strPath);
            return classes;
        } catch (URISyntaxException e) {
            throw new IocException("未找到资源,请检查扫描路劲是否正确!");
        }
    }

    /**
     * 递归扫描所有的包路径
     * @param rootPath 根路径
     */
    public static void recursionPath(URI rootPath){
        File file = new File(rootPath);
        if (file.isDirectory()) {
            File[] fileList = file.listFiles();
            for (int j = 0; j < fileList.length; j++) {
                //处理每个包里面所包含的类
                handlePackageFileClasses(fileList[j]);

                if (fileList[j].isDirectory()) {
                    String path = fileList[j].getPath();
                    URI uri = new File(path).toURI();
                    recursionPath(uri);
                }
            }
        }

    }

    /**
     * 文件处理
     * @param file
     */
    private static void handlePackageFileClasses(File file) {
        //文件筛选
        file.listFiles(new FileFilter() {
            public boolean accept(File file) {
                String path = file.getPath();
                String s = path.replace("\\", ".").split(packages)[1];
                String totalPath=packages+s.replace(".class", "");
                if (file.getName().endsWith(".class") && !file.getName().contains("Servlogger.info(totalPath);let")) {
                    //存入ioc容器
                    putClassWithAnnonInIoc(totalPath);
                    return true;
                }
                return false;
            }
        });
    }

    /**
     * 处理注解
     * @param clazz
     * @return
     * @throws Exception
     */
    private static Ioc handleAnnotation(Class clazz) throws Exception {
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        if (annotations == null || annotations.length == 0) {
            return null;
        }

        //处理每个注解
        for (int i = 0; i < annotations.length; i++) {
            if(!(annotations[i] instanceof Ioc)){
                continue;
            }
            Ioc annotation= (Ioc) annotations[i];
            String id = annotation.value();
            //用户没设置id,使用默认配置
            if(StringUtils.isEmpty(id)){
                return defaultHandleAnnonMechanism(clazz, annotation);
            }
            //用户设置了id，返回用户的配置
            return annotation;
        }
        return null;
    }

    private static Ioc defaultHandleAnnonMechanism(Class clazz, Ioc annotation) throws NoSuchFieldException, IllegalAccessException {
        InvocationHandler handler = Proxy.getInvocationHandler(annotation);
        Field f = handler.getClass().getDeclaredField("memberValues");
        f.setAccessible(true);

        Map<String, Object> memberValues=null;
        memberValues = (Map<String, Object>) f.get(handler);
        Object oldValue = memberValues.get("value");

        memberValues.put("value", StringCaseUtil.lowerFirst( clazz.getSimpleName()));
        return annotation;
    }

    private static void putClassWithAnnonInIoc(String classPath){
        try {
            resolutionClass(classPath);
        } catch (Exception e) {
            throw new IocException("存入ioc容器失败！");
        }
    }

    private static void resolutionClass(String classPath) throws Exception {
        //cn.ycy.core.IOC
        Class<?> clazz = classLoader.loadClass(classPath);
        //处理注解信息，并且设置默认注解信息
        Ioc annotation = handleAnnotation(clazz);
        if(annotation!=null){
            Object classImpl = getClassImpl(clazz);
            //存入ioc容器
            ioc.put(annotation.value(), classImpl);
            putImplToInterface(clazz, classImpl);
            classes.add(clazz);
        }
    }

    private static void putImplToInterface(Class<?> clazz, Object classImpl) {
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            String interfaceIocKey = StringCaseUtil.lowerFirst(anInterface.getSimpleName());
            ioc.put(interfaceIocKey,classImpl);
            classes.add(anInterface);
        }
    }


    private static Object getClassImpl(Class<?> clazz) throws Exception {
        //不是接口，返回具体实现
        if(!clazz.isInterface()){
            Object impl = clazz.newInstance();
            return impl;
        }

//        //todo
//        //找到接口的实现类
//        ServiceLoader<? extends Class> load = ServiceLoader.load(clazz.getClass());
//        Iterator<? extends Class> iterator = load.iterator();
//        while (iterator.hasNext()) {
////            IocApplication.getApplication().get("");
//
//            Class classImpl = iterator.next();
//            return classImpl.newInstance();
//        }
        return null;
    }

}
